﻿using System;
using System.Linq;
using System.Windows.Forms;
using System.Net.FtpClient;
using System.Net;
using System.IO;
using System.Threading;
using VNPT.Utility;
using System.Collections.Generic;

namespace VNPT.DoiSoat
{
    public partial class uFTPExplorer : Core.uBase
    {
        public uFTPExplorer()
        {
            InitializeComponent();
        }

        private bool OpentFTP()
        {
            DoiSoatSetting.FTP_SERVER = txtServer.Text;
            DoiSoatSetting.FTP_USER = txtUser.Text;
            DoiSoatSetting.FTP_PASS = txtPass.Text;

            conn.Host = DoiSoatSetting.FTP_SERVER;
            conn.Credentials = new NetworkCredential(DoiSoatSetting.FTP_USER, DoiSoatSetting.FTP_PASS);
            try
            {
               conn.DataConnectionType = FtpDataConnectionType.AutoActive;
               conn.Connect();

                return true;
            }
            catch (Exception ex)
            {
                DevExpress.XtraEditors.XtraMessageBox.Show(ex.Message, "Xác nhận!",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }
        public override void LoadSetting()
        {
            Load();
            base.LoadSetting();
        }
        public void Load()
        {
            txtServer.Text = DoiSoatSetting.FTP_SERVER;
            txtUser.Text = DoiSoatSetting.FTP_USER;
            txtPass.Text = DoiSoatSetting.FTP_PASS;
        }

        System.Net.FtpClient.FtpClient conn = new System.Net.FtpClient.FtpClient();
        List<string> _LocalPath = new List<string>();
        string _RemoPath;

        private void btnConnect_Click(object sender, EventArgs e)
        {
            using (new DevExpress.Utils.WaitDialogForm("Xin vui lòng chờ..."))
            {

                if (!btnUp.Enabled)
                {
                    if (OpentFTP())
                    {
                        GetAllFile();
                    }
                }
                else
                {
                    conn.Disconnect();
                    bindingSource1.DataSource = typeof(System.Net.FtpClient.FtpListItem);
                }
                if (conn.IsConnected)
                {
                    btnUp.Enabled = true;
                    btnNewFolder.Enabled = true;
                    btnDelete.Enabled = true;
                    btnDownload.Enabled = true;
                    btnUpLoad.Enabled = true;
                    btnRefresh.Enabled = true;
                    btnRename.Enabled = true;
                    txtServer.Enabled = !true;
                    txtPass.Enabled = !true;
                    txtUser.Enabled = !true;
                    btnConnect.Text = "DisConnect";
                }
                else
                {
                    btnUp.Enabled = !true;
                    btnNewFolder.Enabled = !true;
                    btnDelete.Enabled = !true;
                    btnDownload.Enabled = !true;
                    btnUpLoad.Enabled = !true;
                    btnRefresh.Enabled = !true;
                    btnRename.Enabled = !true;
                    txtServer.Enabled = true;
                    txtPass.Enabled = true;
                    txtUser.Enabled = true;
                    btnConnect.Text = "Connect";
                }
            }
        }

        private void SetPath()
        {
           myTextEdit1.Text = conn.GetWorkingDirectory();
        }
       
        private void btnUp_Click(object sender, EventArgs e)
        {
            using (new DevExpress.Utils.WaitDialogForm("Đang đọc dữ liệu..."))
            {
                conn.SetWorkingDirectory("..");
                GetAllFile();
                SetPath();
            }

        }

        private void btnNewFolder_Click(object sender, EventArgs e)
        {
            new fNewFolder(conn).ShowDialog();
            GetAllFile();
            SetPath();
        }

        private void Xoa()
        {
            if (this.bindingSource1.Current != null)
            {
                var t = (System.Net.FtpClient.FtpListItem)this.bindingSource1.Current;
                if (DevExpress.XtraEditors.XtraMessageBox.Show(string.Format("Bạn có chắc xóa {0} không?", t.Name), "Xác nhận?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    switch (t.Type)
                    {
                        case FtpFileSystemObjectType.File:
                            conn.DeleteFile(t.FullName);
                            break;
                        case FtpFileSystemObjectType.Directory:
                            conn.DeleteFile(t.FullName);
                            break;
                        case FtpFileSystemObjectType.Link:
                            DevExpress.XtraEditors.XtraMessageBox.Show("Không thể xóa link", "Xác nhận?", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                            break;
                        default:
                            break;
                    }
                    GetAllFile();
                }
            }
        }
       
        private void btnDelete_Click(object sender, EventArgs e)
        {
            Xoa();
            SetPath();
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            GetAllFile();
            SetPath();
        }

        private void btnDownload_Click(object sender, EventArgs e)
        {
            if (this.bindingSource1.Current != null)
            {
                var t = (System.Net.FtpClient.FtpListItem)this.bindingSource1.Current;
                if (t.Type== FtpFileSystemObjectType.File)
                {
                    using (var dlg = new SaveFileDialog())
                    {
                        dlg.FileName = t.Name;
                        if (dlg.ShowDialog() == DialogResult.OK)
                        {
                            _isDownload = true;
                            _LocalPath.Add(dlg.FileName);
                            _RemoPath = t.FullName;
                            panelControl1.Enabled = false;
                            gridControl1.Enabled = false;
                            backgroundWorker1.RunWorkerAsync();
                        }
                    }
                }
                
            }
            SetPath();
        }

        private void btnUpLoad_Click(object sender, EventArgs e)
        {
            using (var dlg = new OpenFileDialog())
            {
                dlg.InitialDirectory = DoiSoatSetting.Folder_LUU;
                dlg.Multiselect = true;
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    _isDownload = !true;
                    dlg.FileNames.All(p =>
                    {
                        _LocalPath.Add(p);
                        return true;
                    });
                    _RemoPath = conn.GetWorkingDirectory();
                }
            }
            panelControl1.Enabled = false;
            gridControl1.Enabled = false;
            backgroundWorker1.RunWorkerAsync();
        }
      
        private void btnRename_Click(object sender, EventArgs e)
        {
            if (this.bindingSource1.Current != null)
            {
                var k = (System.Net.FtpClient.FtpListItem)this.bindingSource1.Current;
                if (k.Type != FtpFileSystemObjectType.Link)
                {
                    var n = new VNPT.Utility.fInputBox(k.Name);
                    var t = n.ShowMe();
                    if (n.DialogResult == DialogResult.OK)
                    {
                        conn.Rename(k.Name, t);
                    }
                }
            }
            GetAllFile();
        }

        private void GetAllFile()
        {
            bindingSource1.DataSource = conn.GetListing(conn.GetWorkingDirectory(), FtpListOption.Modify | FtpListOption.Size).OrderByDescending(p => p.Type);
        }

        private void gridView1_RowCellClick(object sender, DevExpress.XtraGrid.Views.Grid.RowCellClickEventArgs e)
        {
            if (e.RowHandle >= 0 && e.Clicks == 2)
            {
                if (this.bindingSource1.Current != null)
                {
                    var t = (System.Net.FtpClient.FtpListItem)this.bindingSource1.Current;
                    if (t.Type == FtpFileSystemObjectType.Directory)
                    {
                        using (new DevExpress.Utils.WaitDialogForm("Đang đọc dữ liệu..."))
                        {
                            conn.SetWorkingDirectory(t.FullName);
                            GetAllFile();
                            SetPath();
                        }
                    }
                    else
                    {
                        btnDownload.PerformClick();
                    }
                }
            }
        }

        delegate void SetTextCallback(string text);

        private void SetText(string value)
        {
            if (this.lblText.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { value });
            }
            else
            {
                this.lblText.Text = value;
            }
        }

        private void gridControl1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (this.bindingSource1.Current != null)
                {
                    var t = (System.Net.FtpClient.FtpListItem)this.bindingSource1.Current;
                    if (t.Type == FtpFileSystemObjectType.Directory)
                    {
                        using (new DevExpress.Utils.WaitDialogForm("Đang đọc dữ liệu..."))
                        {
                            conn.SetWorkingDirectory(t.FullName);
                            GetAllFile();
                        }
                    }
                }
            }
            if (e.KeyCode == Keys.Back)
            {
                btnUp.PerformClick();
            }
            if (e.KeyCode == Keys.Delete)
            {
                btnDelete.PerformClick();
            }
            if (e.KeyCode == Keys.F5)
            {
                btnRefresh.PerformClick();
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            progressBarControl1.EditValue = e.ProgressPercentage;
        }

        private void Download(FtpClient ftp, string remoteFilePath, string localFilePath)
        {
            using (var fs = new FileStream(localFilePath, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                var buffer = new byte[8192];
                var offset = 0;
                var remoteStream = ftp.OpenRead(remoteFilePath);
                try
                {
                    while (offset < remoteStream.Length)
                    {
                        try
                        {
                            int len;
                            while ((len = remoteStream.Read(buffer, 0, buffer.Length)) > 0)
                            {
                                fs.Write(buffer, 0, len);
                                var t = string.Format("Tải về {0} {1:n0} kb...", remoteFilePath.Right(25), remoteStream.Position);
                                SetText(t);
                                backgroundWorker1.ReportProgress((int)(remoteStream.Position *100 / remoteStream.Length));
                                offset += len;
                            }
                        }
                        catch (IOException ex)
                        {
                            if (ex.InnerException != null)
                            {
                                var iex = ex.InnerException as System.Net.Sockets.SocketException;
                                if (iex != null && iex.ErrorCode == 10054)
                                {
                                    remoteStream.Close();
                                    remoteStream = ftp.OpenRead(remoteFilePath, restart: offset);
                                }
                                else throw;
                            }
                            else throw;
                        }
                    }
                }
                finally
                {
                    remoteStream.Close();
                }
            }
        }

        private void Upload(FtpClient ftp, string localFilePath, string remoteFilePath)
        {
            using (var fs = new FileStream(localFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                Upload_stream(ftp: ftp, stream: fs, remoteFilePath: remoteFilePath);
            }
        }

        private void Upload_stream(FtpClient ftp, Stream stream, string remoteFilePath)
        {
            var buffer = new byte[8192];
            var offset = 0;
            var remoteStream = ftp.OpenWrite(remoteFilePath);
            try
            {
                while (offset < stream.Length)
                {
                    try
                    {
                        int len;
                        while ((len = stream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            remoteStream.Write(buffer, 0, len);

                            var t = string.Format("Tải lên {0} {1:n0} kb...", remoteFilePath.Right(25), remoteStream.Position);
                            SetText(t);
                            backgroundWorker1.ReportProgress((int)(stream.Position * 100 / stream.Length));

                            offset += len;
                        }
                    }
                    catch (IOException ex)
                    {
                        if (ex.InnerException != null)
                        {
                            var iex = ex.InnerException as System.Net.Sockets.SocketException;
                            if (iex != null && iex.ErrorCode == 10054)
                            {
                                remoteStream.Close();
                                remoteStream = ftp.OpenAppend(remoteFilePath);
                                remoteStream.Position = offset;
                            }
                            else throw;
                        }
                        else throw;
                    }
                }
            }
            finally
            {
                remoteStream.Close();
            }
        }

        private void Download_Upload(bool isDownload)
        {
            if (isDownload)
            {
                Download(conn, _RemoPath, _LocalPath.First());
                _LocalPath.Clear();
            }
            else
            {
                foreach (var item in _LocalPath)
                {
                    Upload(conn,item,_RemoPath+"/"+ Path.GetFileName(item));
                }
                _LocalPath.Clear();
            }
        }
        bool _isDownload = true;
        
        private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            Download_Upload(_isDownload);
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            panelControl1.Enabled = !false;
            gridControl1.Enabled = !false;
            DevExpress.XtraEditors.XtraMessageBox.Show("Đã hoàn thành, vui lòng kiểm tra lại!", "Thông báo!", MessageBoxButtons.OK, MessageBoxIcon.Information);
            btnRefresh.PerformClick();
        }
    }
}
